{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 本地调用内网tool工具\n",
    "\n",
    "在完成Client与知识库交互的需求时，存在客户不想把数据信息上传到云端，而是希望在本地完成数据交互的需求,下面将展示一个调用内网tool工具的简单示例。查询本地信息\n",
    "\n",
    "##### 配置运行环境&导入Client应用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import appbuilder\n",
    "\n",
    "# AppBuilder Token，替换为您个人的Token\n",
    "os.environ[\"APPBUILDER_TOKEN\"] = \"your api key\"\n",
    "\n",
    "# 应用为：智能问题解决者\n",
    "app_id = \"b9473e78-754b-463a-916b-f0a9097a8e5f\"\n",
    "app_client = appbuilder.AppBuilderClient(app_id)\n",
    "conversation_id = app_client.create_conversation()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 首次提问一个问题，应用不具备该能力，通过回答可以印证\n",
    "\n",
    "- 由于并没有关于张三同学的信息，所以Agent无法实现查询"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "message_1 = app_client.run(\n",
    "    conversation_id=conversation_id,\n",
    "    query=\"请问本公司的张三同学的生日是哪天？\",\n",
    ")\n",
    "print(\"Agent第一次回答: {}\".format(message_1.content.answer))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**output**\n",
    "```\n",
    "Agent第一次回答: 为了回答这个问题，我们首先需要明确几个关键点：\n",
    "\n",
    "1. **问题理解**：\n",
    "   - 需要确定的是“张三同学的生日”。\n",
    "\n",
    "2. **工具选择**：\n",
    "   - 由于问题涉及的是特定个人的信息（张三的生日），这通常不是通过工具或系统查询能得到的，而是需要通过公司内部的人事记录或直接询问张三本人来获取。\n",
    "\n",
    "3. **解决方案生成**：\n",
    "   - **步骤一**：首先，尝试访问公司的人事系统或员工档案，看是否有张三的生日信息记录。\n",
    "   - **步骤二**：如果人事系统或员工档案中没有相关信息，或者你不具备访问权限，那么可以考虑直接询问张三本人或其同事，看是否有人知道他的生日。\n",
    "   - **步骤三**：如果以上方法都不可行，还可以尝试联系公司的人力资源部门，看他们是否能提供相关信息。\n",
    "\n",
    "4. **注意事项**：\n",
    "   - 在尝试获取张三的生日信息时，要确保遵守公司的隐私政策和相关法律法规，不要侵犯张三的隐私权。\n",
    "   - 如果张三不愿意透露他的生日信息，应尊重他的选择，并停止进一步询问。\n",
    "\n",
    "5. **可能遇到的问题**：\n",
    "   - 人事系统或员工档案中可能没有张三的生日信息。\n",
    "   - 张三或其同事可能不愿意透露生日信息。\n",
    "   - 人力资源部门可能因隐私政策而无法提供相关信息。\n",
    "\n",
    "综上所述，要确定张三的生日，最直接且尊重隐私的方法是直接询问张三本人，或者通过公司正式渠道（如人力资源部门）在遵守隐私政策的前提下进行查询。\n",
    "```\n",
    "\n",
    "\n",
    "##### 赋予应用一个本地查询组件能力\n",
    "\n",
    "- 这里我们使用info_dict模拟一个数据库查询的返回结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_person_infomation(name: str):\n",
    "    info_dict = {\n",
    "        \"张三\": \"1980年1月1日\",\n",
    "        \"李四\": \"1975年12月31日\",\n",
    "        \"刘伟\": \"1990年12月30日\"\n",
    "    }\n",
    "\n",
    "    if name in info_dict:\n",
    "        return f\"您要查找的{name}的生日是：{info_dict[name]}\"\n",
    "    else:\n",
    "        return f\"您要查找的{name}的信息我们暂未收录，请联系管理员添加。\"\n",
    "    \n",
    "# 创建工具的描述：json_schema格式\n",
    "tools = [\n",
    "    {\n",
    "        \"type\": \"function\",\n",
    "        \"function\": {\n",
    "            \"name\": \"get_person_infomation\",\n",
    "            \"description\": \"查找公司内指定人员的信息\",\n",
    "            \"parameters\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                    \"name\": {\n",
    "                        \"type\": \"string\",\n",
    "                        \"description\": \"人员名称，例如：张三、李四\",\n",
    "                    },\n",
    "                },\n",
    "                \"required\": [\"name\"],\n",
    "            },\n",
    "        },\n",
    "    }\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 现在我们已经完成了本地tool组件的设计，接下来我们将tool的功能赋予Client应用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "message_2 = app_client.run(\n",
    "    conversation_id=conversation_id,\n",
    "    query=\"请问本公司的张三同学的生日是哪天？\",\n",
    "    tools=tools\n",
    ")\n",
    "print(\"Agent的中间思考过程：\")\n",
    "print(message_2.content.events[-1].model_dump_json(indent=4))\n",
    "print(\"Agent思考结束，等待我们上传本地结果\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**output**\n",
    "这部分输出为Client应用的思考过程\n",
    "```\n",
    "Agent的中间思考过程：\n",
    "{\n",
    "    \"code\": 0,\n",
    "    \"message\": \"\",\n",
    "    \"status\": \"interrupt\",\n",
    "    \"event_type\": \"Interrupt\",\n",
    "    \"content_type\": \"contexts\",\n",
    "    \"detail\": {\n",
    "        \"text\": {\n",
    "            \"function_call\": {\n",
    "                \"thought\": \"用户想要查询公司内张三同学的生日信息，这个需求很明确，且背景信息也足够。我可以使用get_person_infomation工具来查找张三的生日信息。\",\n",
    "                \"name\": \"get_person_infomation\",\n",
    "                \"arguments\": {\n",
    "                    \"name\": \"张三\"\n",
    "                },\n",
    "                \"usage\": {\n",
    "                    \"prompt_tokens\": 697,\n",
    "                    \"completion_tokens\": 87,\n",
    "                    \"total_tokens\": 784,\n",
    "                    \"name\": \"ERNIE-4.0-Turbo-8K\",\n",
    "                    \"type\": \"plan\"\n",
    "                },\n",
    "                \"tool_call_id\": \"c23309f7-e24a-4476-85e2-3ef9cfd4f6ed\"\n",
    "            },\n",
    "            \"used_tool\": []\n",
    "...\n",
    "    ]\n",
    "}\n",
    "Agent思考结束，等待我们上传本地结果\n",
    "```\n",
    "\n",
    "- 大模型下发了调用本地函数的参数，我们使用这个参数调用本地函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tool_call = message_2.content.events[-1].tool_calls[-1]\n",
    "tool_call_id = tool_call.id\n",
    "tool_call_argument = tool_call.function.arguments\n",
    "local_func_result = get_person_infomation(**tool_call_argument)\n",
    "print(\"local_func_result: {}\\n\".format(local_func_result))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**output**\n",
    "```\n",
    "local_func_result: 您要查找的张三的生日是：1980年1月1日\n",
    "```\n",
    "\n",
    "- 向应用返回本地运行的结果，完成本地函数toolcall调用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "message_3 = app_client.run(\n",
    "    conversation_id=conversation_id,\n",
    "    tool_outputs=[{\n",
    "        \"tool_call_id\": tool_call_id,\n",
    "        \"output\": local_func_result\n",
    "    }]\n",
    ")\n",
    "print(\"Agent 拥有了本地函数调用能力后，回答是: {}\".format(message_3.content.answer))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**output**\n",
    "```\n",
    "Agent的中间思考过程：\n",
    "{\n",
    "    \"code\": 0,\n",
    "    \"message\": \"\",\n",
    "    \"status\": \"interrupt\",\n",
    "    \"event_type\": \"Interrupt\",\n",
    "    \"content_type\": \"contexts\",\n",
    "    \"detail\": {\n",
    "        \"text\": {\n",
    "            \"function_call\": {\n",
    "                \"thought\": \"用户想要查询公司内张三同学的生日信息，这个需求很明确，且背景信息也足够。我可以使用get_person_infomation工具来查找张三的生日信息。\",\n",
    "                \"name\": \"get_person_infomation\",\n",
    "                \"arguments\": {\n",
    "                    \"name\": \"张三\"\n",
    "                },\n",
    "                \"usage\": {\n",
    "                    \"prompt_tokens\": 697,\n",
    "                    \"completion_tokens\": 87,\n",
    "                    \"total_tokens\": 784,\n",
    "                    \"name\": \"ERNIE-4.0-Turbo-8K\",\n",
    "                    \"type\": \"plan\"\n",
    "                },\n",
    "                \"tool_call_id\": \"c23309f7-e24a-4476-85e2-3ef9cfd4f6ed\"\n",
    "            },\n",
    "            \"used_tool\": []\n",
    "...\n",
    "    ]\n",
    "}\n",
    "Agent思考结束，等待我们上传本地结果\n",
    "\n",
    "Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...\n",
    "\n",
    "local_func_result: 您要查找的张三的生日是：1980年1月1日\n",
    "\n",
    "Agent 拥有了本地函数调用能力后，回答是: # 解决方案\n",
    "\n",
    "## 问题分析\n",
    "\n",
    "用户想要查询公司内张三同学的生日信息。这是一个明确且具体的需求，我们可以通过`get_person_infomation`工具来获取这一信息。\n",
    "\n",
    "## 工具运用\n",
    "\n",
    "1. **工具选择**：`get_person_infomation`\n",
    "2. **参数设置**：\n",
    "\n",
    "\t* `name`：张三\n",
    "\n",
    "3. **执行结果**：张三的生日是1980年1月1日。\n",
    "\n",
    "## 解决方案步骤\n",
    "\n",
    "1. 使用`get_person_infomation`工具，并设置参数`name`为“张三”。\n",
    "2. 等待工具执行，并获取张三的生日信息。\n",
    "3. 将获取到的生日信息（1980年1月1日）告知用户。\n",
    "\n",
    "## 注意事项\n",
    "\n",
    "* 确保在使用`get_person_infomation`工具时，输入的姓名与公司内部记录的姓名完全一致，以避免查询错误。\n",
    "* 如果工具返回“未找到”或类似结果，请检查姓名是否有误或联系公司人事部门确认信息。\n",
    "\n",
    "通过上述步骤，我们可以准确地回答用户的问题，并提供张三的生日信息。\n",
    "```"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "python-12",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
